#include "stdafx.h"
#include "global.h"
#include "deblocking.h"

static const BYTE ALPHA_TABLE[52]  = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,4,4,5,6,  7,8,9,10,12,13,15,17,  20,22,25,28,32,36,40,45,  50,56,63,71,80,90,101,113,  127,144,162,182,203,226,255,255} ;
static const BYTE  BETA_TABLE[52]  = {0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,2,2,2,3,  3,3,3, 4, 4, 4, 6, 6,   7, 7, 8, 8, 9, 9,10,10,  11,11,12,12,13,13, 14, 14,   15, 15, 16, 16, 17, 17, 18, 18} ;
static const byte CLIP_TAB[52][5]  =
{
  { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},
  { 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},{ 0, 0, 0, 0, 0},
  { 0, 0, 0, 0, 0},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 0, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 0, 1, 1, 1},{ 0, 1, 1, 1, 1},
  { 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 1, 1},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 1, 2, 2},{ 0, 1, 2, 3, 3},
  { 0, 1, 2, 3, 3},{ 0, 2, 2, 3, 3},{ 0, 2, 2, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 2, 3, 4, 4},{ 0, 3, 3, 5, 5},{ 0, 3, 4, 6, 6},{ 0, 3, 4, 6, 6},
  { 0, 4, 5, 7, 7},{ 0, 4, 5, 8, 8},{ 0, 4, 6, 9, 9},{ 0, 5, 7,10,10},{ 0, 6, 8,11,11},{ 0, 6, 8,13,13},{ 0, 7,10,14,14},{ 0, 8,11,16,16},
  { 0, 9,12,18,18},{ 0,10,13,20,20},{ 0,11,15,23,23},{ 0,13,17,25,25}
} ;

int MB1_Frame = 1;
int MB2_Frame = 1;
int MB1_Intra = 1;
int MB2_Intra = 1;
int MbaffFrameFlag = 1;
int field_pic_flag = 0;
int mixedModeEdgeFlag = 0;
int MB1_transform_size_8x8_flag = 0;
int MB2_transform_size_8x8_flag = 0;
int diff_reference = 0;
int MB1_VectorNum = 3;
int MB2_VectorNum = 3;

int GetSlice(DWORD MB_Num, MBlock *Image)
{
	MBlock MB = Image[MB_Num];
	if (MB._00._00 < 300)
		return 4;
	else
		return 0;
}

int Deblock(MBlock *Image, DWORD Opt)
{
	int FilterLine[8];
	MBlock *pMB = Image;
	DWORD NoLeft = 1;
	DWORD NoTop;
	DWORD Strenght;
	for (DWORD MacroBlock = 0; MacroBlock < 396; MacroBlock ++)
	{
		if (MacroBlock < 22)		NoTop = 1; else NoTop = 0;
		if (MacroBlock % 22 == 0)	NoLeft = 1; else NoLeft = 0;
		Block *pB = (Block *)pMB;
		Block *pBNeighbour;
		MBlock *pMBNeighbour;
		for (DWORD B = 0; B < 16; B++)
		{
			//Horizontal
			if (B < 4)
			{
				if (!NoTop)
				{
					pMBNeighbour = pMB - 22;
					pBNeighbour = (Block*)pMBNeighbour + 12 + B;
				}
				else 
					pBNeighbour = 0;
			}
			else
				pBNeighbour = pB - 4;
			if (pBNeighbour)
			{
			if (Opt) 
				GetStrenghtOpt(Image, MacroBlock, B, STRENGHT_TOP, &Strenght);
			else
				GetStrenght(Image, MacroBlock, B, STRENGHT_TOP, &Strenght);
				for (DWORD BordNum = 0; BordNum < 4; BordNum ++)
				{
					for (DWORD i = 0; i < 4; i++)
					{
						FilterLine[i] = ((ColorMask*) pBNeighbour)[BordNum + (i << 2)].y;
						FilterLine[i + 4] = ((ColorMask*)pB)[BordNum + (i << 2)].y;
					}
					// Filtration
					Filter(FilterLine, (Strenght >> (BordNum << 3)) & 0xff);
					for (DWORD i = 0; i < 4; i++)
					{
						((ColorMask*) pBNeighbour)[BordNum + (i << 2)].y = FilterLine[i];
						((ColorMask*)pB)[BordNum + (i << 2)].y = FilterLine[i + 4];
					}
				}
			}
			// Vertical
			if (B % 4 == 0)
			{
				if (!NoLeft)
				{
					pMBNeighbour = pMB - 1;
					pBNeighbour = (Block *) pMBNeighbour + B + 3;
				}
				else pBNeighbour = 0;
			}
			else
			{
				pBNeighbour = pB - 1;
			}
			if (pBNeighbour)
			{
				for (DWORD BordNum = 0; BordNum < 16; BordNum += 4)
				{
					for (DWORD i = 0; i < 4; i++)
					{
						FilterLine[i] = ((ColorMask*)pBNeighbour)[BordNum + i].y;
						FilterLine[i + 4] = ((ColorMask*)pB)[BordNum + i].y;
					}
					// Filtration
					if (Opt) 
						GetStrenghtOpt(Image, MacroBlock, B, STRENGHT_LEFT, &Strenght);
					else
						GetStrenght(Image, MacroBlock, B, STRENGHT_LEFT, &Strenght);
					Filter(FilterLine, (Strenght >> (BordNum << 3)) & 0xff);
					for (DWORD i = 0; i < 4; i++)
					{
						((ColorMask*) pBNeighbour)[BordNum + i].y = FilterLine[i];
						((ColorMask*)pB)[BordNum + i].y = FilterLine[i + 4];
					}
				}
			}
			pB++;
		}
		pMB++;
	}
	return 1;
}
// FL:	0  1  2  3  4  5  6  7
// P&Q: P3 P2 P1 P0 Q0 Q1 Q2 Q3
int Filter(int *FL, DWORD Strenght)
{
	int indexA = 35;
	int indexB = 35;
	int Ap = abs(FL[6] - FL[4]);
	int Aq = abs(FL[1] - FL[3]);
	int Beta = BETA_TABLE[indexB];
	int Alpha = ALPHA_TABLE[indexA];
	if (Strenght < 4)
	{
		int tc0 = CLIP_TAB[indexA][Strenght];
		int tc = tc = tc0 + (Ap < Beta) + (Aq < Beta);
		
		int Delta = Clip3(-tc,tc, ((((FL[4] - FL[3]) << 2) + (FL[2] - FL[5]) + 4) >> 3));  
		
		FL[2] = FL[2] + Clip3(-tc0,tc0,(FL[1] + ((FL[4] + FL[3] + 1) >> 1) - (FL[2] << 1)) >> 1);
		FL[5] = FL[5] + Clip3(-tc0,tc0,(FL[6] + ((FL[4] + FL[3] + 1) >> 1) - (FL[5] << 1)) >> 1);

		FL[3] = Clip1(FL[3] + Delta);
		FL[4] = Clip1(FL[4] - Delta);
	}
	else
	{
// FL:	0  1  2  3  4  5  6  7
// P&Q: P3 P2 P1 P0 Q0 Q1 Q2 Q3
		int FL0[8];
		memcpy(FL0, FL, sizeof(FL0));
		if ((Ap < Beta) && abs(FL[3]-FL[4]) < ((Alpha >> 2) + 2))
		{
			FL[3] = (FL0[1] + 2 * FL0[2] + 2 * FL0[3] + 2 * FL0[4] + FL0[5] + 4) >> 3;
			FL[2] = (FL0[1] + FL0[2] + FL0[3] + FL0[4] + 2) >> 2;
			FL[1] = (2 * FL0[0] + 3 * FL0[1] + FL0[2] + FL0[3] + FL0[4] + 4) >> 3;
		}
		if ((Aq < Beta) && (abs(FL[3] - FL[4]) < ((Alpha >> 2) + 2)))
		{
			FL[4] = (FL0[2] + 2 * FL0[3] + 2 * FL0[4] + 2 * FL0[5] + FL0[6] + 4) >> 3;
			FL[5] = (FL0[3] + FL0[4] + FL0[5] + FL0[6] + 2) >> 2;
			FL[6] = (2 * FL0[7] + 3 * FL0[6] + FL0[5] + FL0[4] + FL0[3] + 4) >> 3;
		}
	}
	return 1;
}

int GetStrenght(MBlock *Image, DWORD MBNum, DWORD BNum, DWORD Direction, DWORD *Strenght)
{
	*Strenght = 0;
	for (int i = 0; i < 4; i++)
	{
		if (Direction == STRENGHT_TOP)
		{
			if (BNum < 4)
			{
				if ((MB1_Frame && MB2_Frame) && (MB1_Intra || MB2_Intra))
					*Strenght += 4 << (i * 8);
				if (MB1_Frame == 1 && MB2_Frame == 1)
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = GetSlice(MBNum - 22, Image);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
				if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_TOP == 1 && (MB1_Intra || MB2_Intra)) *Strenght += 0;
				if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_TOP == 1)
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = GetSlice(MBNum - 22, Image);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
			}
			else
			{
				if (mixedModeEdgeFlag == 0 && (MB1_Intra || MB2_Intra))
					*Strenght += 3 << (i * 8);
				if (mixedModeEdgeFlag == 0)
				{
					int S1 = GetSlice(MBNum, Image);
			//		int S2 = GetSlice(MBNum - 22, Image);
					int S2 = 4;
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
				if (mixedModeEdgeFlag == 1 && Direction == STRENGHT_TOP && (MB1_Intra || MB2_Intra))
					*Strenght += 0;
				if ((mixedModeEdgeFlag == 1) && (Direction == STRENGHT_TOP))
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = 4;
				//	int S2 = GetSlice(MBNum - 22, Image);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
			}
			if (MB1_transform_size_8x8_flag == 1 && (Image[MBNum]._00._00 & 0xff) > 256) *Strenght += 2 << (i * 8);
			if (MB1_transform_size_8x8_flag == 0 && (Image[MBNum]._00._00 & 0xff) > 512) *Strenght += 2 << (i * 8);
			if (MB2_transform_size_8x8_flag == 1 && (Image[MBNum]._33._33 & 0xff) < 256) *Strenght += 2 << (i * 8);
			if (MB2_transform_size_8x8_flag == 0 && (Image[MBNum]._33._33 & 0xff) > 512) *Strenght += 2 << (i * 8);

			if (mixedModeEdgeFlag == 1) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && diff_reference == 1)  *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 1 && MB2_VectorNum == 1) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && diff_reference == 2 && MB1_VectorNum == 2) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 2 && MB2_VectorNum == 2)  *Strenght += 1 << (i * 8);
		}
		if (Direction == STRENGHT_LEFT)
		{
			if (BNum % 4 == 0)
			{
				if ((MB1_Frame && MB2_Frame) && (MB1_Intra || MB2_Intra))
					*Strenght += 4 << (i * 8);
				if ((MB1_Frame == 1 && MB2_Frame == 1))
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = GetSlice(MBNum, Image - 1);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
				if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_LEFT == 1 && (MB1_Intra || MB2_Intra)) *Strenght += 0;
				if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_LEFT == 1)
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = GetSlice(MBNum, Image - 1);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
			}
			else
			{
				if (mixedModeEdgeFlag == 0 && (MB1_Intra || MB2_Intra))
					*Strenght += 3 << (i * 8);
				if (mixedModeEdgeFlag == 0)
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = 4;
					//int S2 = GetSlice(MBNum, Image - 1);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
				if (mixedModeEdgeFlag == 1 && Direction == STRENGHT_LEFT && (MB1_Intra || MB2_Intra))
					*Strenght += 0;
				if ((mixedModeEdgeFlag == 1) && (Direction == STRENGHT_LEFT))
				{
					int S1 = GetSlice(MBNum, Image);
					int S2 = 4;
					//int S2 = GetSlice(MBNum, Image - 1);
					if (S1 == 4 && S2 == 4) *Strenght += 0;
				}
			}
			if (MB1_transform_size_8x8_flag == 1 && (Image[MBNum]._00._00 & 0xff) > 256) *Strenght += 2 << (i * 8);
			if (MB1_transform_size_8x8_flag == 0 && (Image[MBNum]._00._00 & 0xff) > 512) *Strenght += 2 << (i * 8);
			if (MB2_transform_size_8x8_flag == 1 && (Image[MBNum]._33._33 & 0xff) < 256) *Strenght += 2 << (i * 8);
			if (MB2_transform_size_8x8_flag == 0 && (Image[MBNum]._33._33 & 0xff) > 512) *Strenght += 2 << (i * 8);

			if (mixedModeEdgeFlag == 1) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && diff_reference == 1)  *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 1 && MB2_VectorNum == 1) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && diff_reference == 2 && MB1_VectorNum == 2) *Strenght += 1 << (i * 8);
			if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 2 && MB2_VectorNum == 2)  *Strenght += 1 << (i * 8);
		}
	}
	return 0;
}

int GetStrenghtOpt(MBlock *Image, DWORD MBNum, DWORD BNum, DWORD Direction, DWORD *Strenght)
{
	*Strenght = 0;
	if (Direction == STRENGHT_TOP)
	{
		if (BNum < 4)
		{
			if ((MB1_Frame && MB2_Frame) && (MB1_Intra || MB2_Intra))
				memset(Strenght, 4, 4);
			if (MB1_Frame == 1 && MB2_Frame == 1)
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = GetSlice(MBNum - 22, Image);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
			if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_TOP == 1 && (MB1_Intra || MB2_Intra)) *Strenght += 0;
			if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_TOP == 1)
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = GetSlice(MBNum - 22, Image);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
		}
		else
		{
			if (mixedModeEdgeFlag == 0 && (MB1_Intra || MB2_Intra))
				memset(Strenght, 3, sizeof(DWORD));
			if (mixedModeEdgeFlag == 0)
			{
				int S1 = GetSlice(MBNum, Image);
		//		int S2 = GetSlice(MBNum - 22, Image);
				int S2 = 4;
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
			if (mixedModeEdgeFlag == 1 && Direction == STRENGHT_TOP && (MB1_Intra || MB2_Intra))
				*Strenght += 0;
			if ((mixedModeEdgeFlag == 1) && (Direction == STRENGHT_TOP))
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = 4;
			//	int S2 = GetSlice(MBNum - 22, Image);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
		}
		if (MB1_transform_size_8x8_flag == 1 && (Image[MBNum]._00._00 & 0xff) < 256) memset(Strenght, 2, sizeof(DWORD));
		if (MB1_transform_size_8x8_flag == 0 && (Image[MBNum]._00._00 & 0xff) > 512) memset(Strenght, 2, sizeof(DWORD));
		if (MB2_transform_size_8x8_flag == 1 && (Image[MBNum]._33._33 & 0xff) < 256) memset(Strenght, 2, sizeof(DWORD));
		if (MB2_transform_size_8x8_flag == 0 && (Image[MBNum]._33._33 & 0xff) > 512) memset(Strenght, 2, sizeof(DWORD));
		if (mixedModeEdgeFlag == 1) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && diff_reference == 1)  memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 1 && MB2_VectorNum == 1) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && diff_reference == 2 && MB1_VectorNum == 2) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 2 && MB2_VectorNum == 2) memset(Strenght, 1, sizeof(DWORD));
	}
	if (Direction == STRENGHT_LEFT)
	{
		if (BNum % 4 == 0)
		{
			if ((MB1_Frame && MB2_Frame) && (MB1_Intra || MB2_Intra))
				memset(Strenght, 4, sizeof(DWORD));
			if ((MB1_Frame == 1 && MB2_Frame == 1))
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = GetSlice(MBNum, Image - 1);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
			if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_LEFT == 1 && (MB1_Intra || MB2_Intra)) *Strenght += 0;
			if ((MbaffFrameFlag == 1 || field_pic_flag == 0) && STRENGHT_LEFT == 1)
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = GetSlice(MBNum, Image - 1);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
		}
		else
		{
			if (mixedModeEdgeFlag == 0 && (MB1_Intra || MB2_Intra))
				memset(Strenght, 3, sizeof(DWORD));
			if (mixedModeEdgeFlag == 0)
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = 4;
				//int S2 = GetSlice(MBNum, Image - 1);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
			if (mixedModeEdgeFlag == 1 && Direction == STRENGHT_LEFT && (MB1_Intra || MB2_Intra))
				*Strenght += 0;
			if ((mixedModeEdgeFlag == 1) && (Direction == STRENGHT_LEFT))
			{
				int S1 = GetSlice(MBNum, Image);
				int S2 = 4;
				//int S2 = GetSlice(MBNum, Image - 1);
				if (S1 == 4 && S2 == 4) *Strenght += 0;
			}
		}
		if (MB1_transform_size_8x8_flag == 1 && (Image[MBNum]._00._00 & 0xff) < 256) memset(Strenght, 2, sizeof(DWORD));
		if (MB1_transform_size_8x8_flag == 0 && (Image[MBNum]._00._00 & 0xff) > 512) memset(Strenght, 2, sizeof(DWORD));
		if (MB2_transform_size_8x8_flag == 1 && (Image[MBNum]._33._33 & 0xff) < 256) memset(Strenght, 2, sizeof(DWORD));
		if (MB2_transform_size_8x8_flag == 0 && (Image[MBNum]._33._33 & 0xff) > 512) memset(Strenght, 2, sizeof(DWORD));
		if (mixedModeEdgeFlag == 1) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && diff_reference == 1)  memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 1 && MB2_VectorNum == 1) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && diff_reference == 2 && MB1_VectorNum == 2) memset(Strenght, 1, sizeof(DWORD));
		if (mixedModeEdgeFlag == 0 && MB1_VectorNum == 2 && MB2_VectorNum == 2) memset(Strenght, 1, sizeof(DWORD));
	}
	return 0;
}